from flask import Flask, render_template, session, redirect, url_for, flash
from functools import wraps
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField, BooleanField, SelectField, IntegerField, PasswordField
from wtforms.validators import DataRequired
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate 
from flask_bootstrap import Bootstrap
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash

app = Flask(__name__)
app.config['SECRET_KEY'] = 'XXX'  # 添加secret_key配置

bootstrap = Bootstrap(app)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:123456@localhost:3306/miracle'

db = SQLAlchemy(app)
migrate = Migrate(app, db)

# 配置Flask-Login
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'  # 设置登录页面的路由
login_manager.login_message = '请先登录以访问此页面。'

# User数据模型
class User(UserMixin, db.Model):
    __tablename__ = "users"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(64), unique=True, nullable=False)
    password_hash = db.Column(db.String(256), nullable=False)
    role = db.Column(db.String(20), nullable=False, default='guest')  # 角色字段：admin或guest
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        return check_password_hash(self.password_hash, password)
    
    def get_id(self):
        return str(self.id)

# 用户加载回调函数
@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 权限检查装饰器
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated:
            return redirect(url_for('login'))
        if current_user.role != 'admin':
            flash('权限不足：只有管理员可以访问此页面。')
            return redirect(url_for('index'))
        return f(*args, **kwargs)
    return decorated_function

class NameForm(FlaskForm):
    id = IntegerField('Id') 
    name = StringField('Name?',validators=[DataRequired()]) 
    # 新增 SelectField，coerce=int 确保表单返回的是整数ID
    major = SelectField('Major', coerce=int)
    submit = SubmitField('Submit') 
   
class EditForm(NameForm):
    submit = SubmitField("Edit") 

# 登录表单
class LoginForm(FlaskForm):
    username = StringField('用户名', validators=[DataRequired()])
    password = PasswordField('密码', validators=[DataRequired()])
    remember_me = BooleanField('记住我')
    submit = SubmitField('登录')

# 注册表单
class RegistrationForm(FlaskForm):
    username = StringField('用户名', validators=[DataRequired()])
    password = PasswordField('密码', validators=[DataRequired()])
    password2 = PasswordField('确认密码', validators=[DataRequired()])
    submit = SubmitField('注册')

class Student(db.Model):
    __tablename__ = "student"
    id = db.Column(db.Integer, primary_key = True, autoincrement = True, nullable = False)
    name = db.Column(db.String(10), nullable = False)
    age = db.Column(db.Integer, nullable = False)
    major_id = db.Column(db.Integer, db.ForeignKey("majors.id"))

class Major(db.Model):
    __tablename__ = 'majors'
    id = db.Column(db.Integer, primary_key=True)
    major_name = db.Column(db.String(100), unique=True, nullable=False)
    # 定义“一对多”关系中的“一”
    # 'students' 是反向引用的名称，'major' 是在 Student_Info 中定义的 backref 名称
    students = db.relationship('Student', backref='major', lazy='dynamic')
    def __repr__(self):
        return f'<Major {self.major_name}>'

# 登录路由
@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('用户名或密码错误')
            return redirect(url_for('login'))
        
        login_user(user, remember=form.remember_me.data)
        flash('登录成功！')
        return redirect(url_for('index'))
    
    return render_template('login.html', form=form)

# 注册路由
@app.route('/register', methods=['GET', 'POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    
    form = RegistrationForm()
    if form.validate_on_submit():
        if form.password.data != form.password2.data:
            flash('两次输入的密码不一致')
            return redirect(url_for('register'))
        
        existing_user = User.query.filter_by(username=form.username.data).first()
        if existing_user:
            flash('用户名已存在')
            return redirect(url_for('register'))
        
        user = User(username=form.username.data)
        user.set_password(form.password.data)
        # 新注册用户默认为guest角色
        user.role = 'guest'
        db.session.add(user)
        db.session.commit()
        
        flash('注册成功！请登录。')
        return redirect(url_for('login'))
    
    return render_template('register.html', form=form)

# 登出路由
@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('您已成功登出。')
    return redirect(url_for('index'))

# 创建管理员账户（仅用于开发测试）
@app.route('/create_admin')
def create_admin():
    # 检查是否已存在管理员账户
    admin_user = User.query.filter_by(username='admin').first()
    if admin_user:
        flash('管理员账户已存在')
        return redirect(url_for('index'))
    
    # 创建管理员账户
    admin = User(username='admin')
    admin.set_password('admin123')  # 默认密码
    admin.role = 'admin'
    db.session.add(admin)
    db.session.commit()
    
    flash('管理员账户已创建，用户名：admin，密码：admin123')
    return redirect(url_for('index'))

@app.route("/",methods=['GET','POST'])
def index():
    studs = Student.query.all()
    majors = Major.query.all() # 查询所有专业
    return render_template('index.html',studs=studs, majors=majors) 

@app.route("/new",methods=['GET','POST'])
@admin_required
def new_stud():
    form = NameForm()
    # 动态填充选项：(value, label) 
    form.major.choices = [(m.id, m.major_name) for m in Major.query.order_by('major_name').all()]
    if form.validate_on_submit():
        id = form.id.data
        name = form.name.data
        # 通过ID获取选择的 Major 对象
        major_obj = Major.query.get(form.major.data)
        newstud = Student(id=id, name=name, age=18, major=major_obj) # 使用正确的字段名
        db.session.add(newstud)
        db.session.commit() 
        flash("a new student record is saved") 
        return redirect(url_for('index')) 
    return render_template("new_stud.html",form=form)

@app.route("/major/add")
def major_add():
    m1 = Major(major_name='计算机科学与技术')
    m2 = Major(major_name='软件工程')
    m3 = Major(major_name='信息管理与信息系统')
    db.session.add_all([m1,m2,m3])
    db.session.commit()
    return "专业添加成功"

@app.route("/edit/<int:stu_id>",methods=["GET","POST"])
@admin_required
def edit_stud(stu_id):
    form=EditForm()
    stud = Student.query.get(stu_id)
    # 同样需要动态填充选项
    form.major.choices = [(m.id, m.major_name) for m in Major.query.order_by('major_name').all()]
    if form.validate_on_submit():
        stud.id=form.id.data
        stud.name = form.name.data
        stud.major = Major.query.get(form.major.data) # 更新关联
        db.session.commit() 
        flash('The record is updated') 
        return redirect(url_for('index'))
    form.id.data=stud.id
    form.name.data = stud.name
    # 页面加载时，设置下拉框的默认选中项
    if stud.major:
        form.major.data = stud.major_id
    return render_template('edit_stud.html',form=form) # 注意使用修复后的模板名

@app.route('/delete/<int:stud_id>')
@admin_required
def del_stud(stud_id):
    stud = Student.query.get(stud_id)
    if stud:
        db.session.delete(stud)
        db.session.commit()
        flash('学生记录已删除')
    return redirect(url_for('index'))

@app.route('/hello',methods=['GET','POST'])
def hello2():
    form = NameForm()
    if form.validate_on_submit():
        oldname = session.get('name')
        if oldname is not None and oldname != form.name.data:
            flash('您的姓名已经更新成功！')
        session['name'] = form.name.data
        return redirect(url_for('hello2'))
    return render_template('user.html',form = form,name = session.get('name'))

@app.route("/major/<int:major_id>")
def filter_by_major(major_id):
    # 找到被点击的专业
    major = Major.query.get_or_404(major_id)
    # 使用 'major' 关系的反向查询 'students'
    studs = major.students.all()
    # 复用 index2.html 模板，但只传入筛选后的学生
    majors = Major.query.all() # 筛选页面也需要专业列表
    return render_template('index.html', studs=studs, majors=majors)

@app.route("/major_information/<major_name>")
def major_information(major_name):
    return render_template("major_information.html", major_name = major_name)

if __name__ == "__main__":
    app.run(debug=True)

